#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<sys/bitypes.h>  //pid_t
#include<unistd.h>       //fork
#include<sys/wait.h>     //waitpid

#define LEFT "[" 
#define RIGHT "]" 
#define LABEL "#"
#define LINE_SIZE 1024
#define DELIMI " "
#define EXIT_CODE 66

char command[LINE_SIZE];
char* _argv[32];
int lastcode=0;
char pwd[LINE_SIZE];
char *myenv[LINE_SIZE];
int myenv_count=0;

const char* getusername(){
    return getenv("USER");
}
const char* gethostname(){
    return getenv("HOSTNAME");
}
void getpwd(){
    getcwd(pwd,sizeof(pwd));
}
void interact(char command[],int size){
    getpwd();
    printf(LEFT"%s@%s %s"RIGHT""LABEL" ",getusername(),gethostname(),pwd);
    char*s=fgets(command,size,stdin);
    assert(s);
    (void)s;

    command[strlen(command)-1]='\0';
}

int splitstring(char*command,char*_argv[]){
    int i=0;
    _argv[i++]=strtok(command,DELIMI);
    while(_argv[i++]=strtok(NULL,DELIMI));
    return i-1;
}

int buildcommand(char* _argv[],int argc){
     if(strcmp(_argv[0],"cd")==0){
         chdir(_argv[1]);
         getpwd();
         sprintf(getenv("PWD"),"%s",pwd);
         return 1;
     }
     else if(strcmp(_argv[0],"export")==0){
         //putenv(_argv[1]); //error:putenv是改变_argv[1]的指向,_argv每次都会改变,所以环境变量会被影响
         strcpy(myenv[myenv_count],_argv[1]);
         putenv(myenv[myenv_count++]);
         return 1;
     }
     else if(strcmp(_argv[0],"echo")==0){
         if(strcmp(_argv[1],"$?")==0){
             printf("%d\n",lastcode);
             lastcode=0;  //注意这里lastcode要刷新
         }
         else if(*_argv[1]=='$'){
             char*val=getenv(_argv[1]+1);
             if(val)
             printf("%s\n",val);
         }
         else{
             printf("%s\n",_argv[1]);
         }
         return 1;
     }


     //对ls命令的特殊处理
     if(strcmp(_argv[0],"ls")==0){
         _argv[argc++]="--color";
         _argv[argc]=NULL;   //注意_argv的最后一个需要为NULL
     }
     return 0;
}

void normalcommand(char*_argv[]){
        pid_t id=fork();
        if(id<0){
            perror("fork");
            return;
         }
        else if(id==0){
            //子进程
        execvp(_argv[0],_argv);
        exit(EXIT_CODE);
        }
        else{
        //等待子进程
        int status=0;
        pid_t ret=waitpid(id,&status,0);   //option=0:阻塞等待
           if(ret==id){
               lastcode=WEXITSTATUS(status);  //子进程的退出码
            }
        }  
}
int main(){
    while(1){
        //1.交互获取命令
        interact(command,LINE_SIZE);
        
        //2.解析命令
        int argc=splitstring(command,_argv);
        if(argc==0){
            continue;
        }
        //3.内建命令
        int ret=buildcommand(_argv,argc);
        //4.创建子进程执行命令
        if(!ret){
            normalcommand(_argv);
        }
    }
    return 0;
}
